import React, { useEffect, useState, useMemo } from 'react';
import _ from 'lodash';
import { nanoid } from 'nanoid';
import {
  Form,
  TreeSelect,
  Input,
  InputNumber,
  Select,
  Radio,
  Button,
  Spin,
  Row,
  Col,
  message,
} from 'antd';
import AntIconSelect from '@/components/AntIconSelect';
import DebounceWrapper from '@/components/DebounceWrapper';
import DraggableModal from '@/components/DraggableModal';
import {
  addResource,
  modifyResource,
  fetchResourceCatalogueFromTree,
} from '@/services/system/resource';
import { fetchAvailableDictChildList } from '@/services/system/dictionary';
import { formatTree } from '@/utils/utils';
import { dynamicRoute } from '@/../config/routes';
import styles from './index.less';

const layout = {
  labelCol: { span: 6 },
  wrapperCol: { span: 16 },
};
const { Group } = Radio;
const { TextArea } = Input;
const DebounceButton = DebounceWrapper(Button);
const keepAliveMappings = [
  { label: '否', value: false },
  { label: '是', value: true },
];
const pathWithShareKey = _.map(
  _.filter(dynamicRoute, (item) => !!item.shareWithParamsKey),
  'path',
);
const pathOptionMappings = _.map(
  _.filter(dynamicRoute, (item) => !item.shareWithParamsKey),
  ({ path, description }) => ({ label: path, value: path, title: description || path }),
);

const checkIsPublicRoutePath = (path) => {
  let isPublicPath;
  for (let i = 0; i < pathWithShareKey.length; i++) {
    const reg = new RegExp('^' + pathWithShareKey[i].replace(/\*$/, ''));
    if (reg.test(path)) {
      isPublicPath = true;
      break;
    }
  }
  return !!isPublicPath;
};

export default ({ visible, options, closeModal, updateList }) => {
  const { id, routePath, sourceParams } = options;
  const [form] = Form.useForm();
  const [initialLoading, setInitialLoading] = useState(true);
  const [resourceTypeDict, setResourceTypeDict] = useState([]);
  const [resourceStatusDict, setResourceStatusDict] = useState([]);
  const [catalogueData, setCatalogueData] = useState([]);
  const [catalogueLoadingId, setCatalogueLoadingId] = useState('');
  const [actionLoading, setActionLoading] = useState(false);
  const [isMenuResource, setIsMenuResource] = useState(false);

  const isPublicRoutePath = useMemo(() => checkIsPublicRoutePath(routePath), [routePath]);

  // 获取字典数据
  const getDictData = async (dictType) => {
    try {
      const res = await fetchAvailableDictChildList({ dictType });
      return _.isArray(res)
        ? _.filter(
            _.map(res, ({ dictValue, dictLabel }) => ({ value: dictValue, label: dictLabel })),
            ({ value }) => _.isString(value) || _.isNumber(value),
          )
        : [];
    } catch (e) {
      return [];
    }
  };
  // 获取目录树
  const getCatalogueData = async () => {
    try {
      const res = await fetchResourceCatalogueFromTree();
      return formatTree(res, ({ id, title }) => ({ title, value: id }));
    } catch (e) {
      return [];
    }
  };

  // 初始化
  useEffect(() => {
    Promise.all([getDictData('resource_type'), getDictData('res_status')]).then((result) => {
      const [resTypeDict, resStatusDict] = result;
      setResourceTypeDict(resTypeDict);
      setResourceStatusDict(resStatusDict);
      setInitialLoading(false);
    });
  }, []);

  // 表单初始化处理
  useEffect(() => {
    if (visible) {
      // 更新目录树
      const nextCatalogueLoadingId = nanoid(12);
      setCatalogueLoadingId(nextCatalogueLoadingId);
      getCatalogueData().then((list) => {
        let validDataFetch;
        setCatalogueLoadingId((currentId) => {
          if (currentId === nextCatalogueLoadingId) {
            validDataFetch = true;
            return '';
          }
          return currentId;
        });
        if (validDataFetch) {
          const rootItem = { title: '顶层', value: '0' };
          if (list && list.length) {
            rootItem.children = list;
          }
          setCatalogueData([rootItem]);
        }
      });
      if (id) {
        const { menuIcon, type, keepAlive, routePath, ...restOpts } = options;
        const isMenu = type === '2';
        const modifyValues = _.assign(
          {},
          _.pick(restOpts, _.map(formList, 'name')),
          {
            type,
            resourceIcon: menuIcon ? { iconName: menuIcon, iconLibrary: 'antD' } : {},
          },
          isMenu ? { routePath, keepAlive } : null,
        );
        // console.log('编辑赋值', options, modifyValues);
        setIsMenuResource(isMenu);
        form.setFieldsValue(modifyValues);
      }
      return;
    }
    setCatalogueData([]);
    setCatalogueLoadingId('');
    setIsMenuResource(false);
    form.resetFields();
  }, [visible]);

  const formList = [
    {
      name: 'resourceIcon',
      label: '资源图标',
      initialValue: {},
      rules: [
        {
          required: true,
          validator: (field, value) => {
            if (_.isEmpty(value)) {
              return Promise.reject(new Error('请选择资源图标'));
            }
            return Promise.resolve();
          },
        },
      ],
      component: AntIconSelect,
      componentProps: {},
    },
    {
      name: 'title',
      label: '资源名称',
      initialValue: '',
      rules: [{ required: true, whitespace: true, message: '请输入资源名称' }],
      component: Input,
      componentProps: {
        maxLength: 24,
        allowClear: true,
        placeholder: '请输入资源名称',
        autoComplete: 'off',
      },
    },
    {
      name: 'type',
      label: '资源类型',
      initialValue: '',
      rules: [{ required: true, message: '请选择资源类型' }],
      component: Group,
      componentProps: {
        disabled: !!id,
        onChange: (e) => {
          setIsMenuResource(e.target.value === '2');
        },
      },
      componentChildren: resourceTypeDict.map(({ label, value }) => (
        <Radio value={value} key={value}>
          {label}
        </Radio>
      )),
    },
    {
      name: 'parentId',
      label: '资源父节点',
      initialValue: undefined,
      rules: [{ required: true, message: '请选择资源父节点' }],
      component: TreeSelect,
      componentProps: {
        allowClear: true,
        treeData: catalogueData,
        placeholder: '请选择资源父节点',
      },
    },
    isMenuResource
      ? {
          name: 'keepAlive',
          label: '菜单缓存',
          tooltip: '开启缓存后，将保留该页面的用户操作记录',
          initialValue: false,
          rules: [{ required: true, message: '请选择缓存状态' }],
          component: Group,
          componentProps: {},
          componentChildren: keepAliveMappings.map(({ label, value }) => (
            <Radio value={value} key={value}>
              {label}
            </Radio>
          )),
        }
      : null,
    isMenuResource
      ? {
          name: 'routePath',
          label: '菜单地址',
          tooltip: '部分通用菜单地址不支持修改',
          initialValue: undefined,
          rules: [{ required: true, message: '请选择菜单地址' }],
          component: Select,
          componentProps: {
            allowClear: true,
            showSearch: true,
            disabled: isPublicRoutePath,
            options: pathOptionMappings,
            placeholder: '请选择菜单地址',
          },
        }
      : null,
    {
      name: 'resStatus',
      label: '资源状态',
      initialValue: _.head(resourceStatusDict)?.value || '',
      rules: [{ required: true, message: '请选择资源状态' }],
      component: Group,
      componentProps: {},
      componentChildren: resourceStatusDict.map(({ label, value }) => (
        <Radio value={value} key={value}>
          {label}
        </Radio>
      )),
    },
    {
      name: 'resSort',
      label: '资源排序',
      initialValue: 1,
      rules: [
        {
          required: true,
          validator: (field, value) => {
            if (value !== '' && value != null) {
              if (/^\d+$/.test(value)) {
                return Promise.resolve();
              }
              return Promise.reject(new Error('请输入正整数'));
            }
            return Promise.reject(new Error('请输入正整数'));
          },
        },
      ],
      component: InputNumber,
      componentProps: {
        min: 1,
        max: 999,
      },
    },
    {
      name: 'description',
      label: '资源描述',
      initialValue: '',
      rules: [],
      component: TextArea,
      labelCol: { xs: { span: 6 }, md: { span: 3 } },
      wrapperCol: { xs: { span: 16 }, md: { span: 20 } },
      componentProps: {
        showCount: true,
        maxLength: 128,
        autoSize: { minRows: 3, maxRows: 5 },
        placeholder: '请输入资源描述',
        autoComplete: 'off',
      },
    },
  ];
  const validFormList = _.filter(formList, (o) => !!o);

  // 取消
  const handleCancel = () => {
    if (!actionLoading) {
      closeModal();
    }
  };
  // 提交
  const handleConfirm = () => {
    form.validateFields().then((values) => {
      setActionLoading(true);
      const { resourceIcon, ...restValue } = values;
      const params = _.assign(
        {},
        restValue,
        { menuIcon: resourceIcon?.iconName || '' },
        isPublicRoutePath ? { sourceParams } : null,
        id ? { id } : null,
      );
      // console.log('提交参数：', params);
      const confirmAction = params.id ? modifyResource : addResource;
      confirmAction(params)
        .then(() => {
          closeModal();
          setActionLoading(false);
          updateList && updateList();
          message.success(`资源${params.id ? '修改' : '新增'}成功`);
        })
        .catch(() => {
          setActionLoading(false);
        });
    });
  };

  return (
    <DraggableModal
      width={780}
      visible={visible}
      title={`资源${id ? '编辑' : '添加'}`}
      onCancel={handleCancel}
      footer={[
        <DebounceButton key="cancel" disabled={actionLoading} onClick={closeModal}>
          取消
        </DebounceButton>,
        <DebounceButton
          key="confirm"
          type="primary"
          loading={actionLoading}
          onClick={handleConfirm}
        >
          提交
        </DebounceButton>,
      ]}
    >
      <Spin spinning={initialLoading || !!catalogueLoadingId} tip={'初始化..'}>
        <div className={styles.resourceFormContainer}>
          <Form {...layout} form={form} name="resource-form">
            <Row>
              {validFormList.map((item, index) => (
                <Col
                  key={item.name}
                  xs={24}
                  md={index === validFormList.length - 1 ? (index % 2 ? 12 : 24) : 12}
                >
                  <Form.Item
                    {..._.pick(item, [
                      'name',
                      'label',
                      'rules',
                      'tooltip',
                      'initialValue',
                      'validateTrigger',
                      'labelCol',
                      'wrapperCol',
                    ])}
                  >
                    {item.component
                      ? React.createElement(
                          item.component,
                          { ...item.componentProps },
                          item.componentChildren,
                        )
                      : null}
                  </Form.Item>
                </Col>
              ))}
            </Row>
          </Form>
        </div>
      </Spin>
    </DraggableModal>
  );
};
